package com.sc.byahi.user.client.components.json;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.google.gwt.json.client.*;
import com.sc.byahi.user.shared.SearchBean;

public class JSONSerializer {
	
	public static void main(String[] args) {
		SearchBean sb = new SearchBean();
		sb.setAgeBegin(18l);
		sb.setAgeEnd(35l);
		sb.setCaste(Arrays.asList("A b", "AB"));
		sb.setDegrees(Arrays.asList("MA", "M Com"));
		sb.setEatingHabits(Arrays.asList("Veg", "Non Veg"));
		sb.setEmploymentType(Arrays.asList("Govr", "Private"));
		sb.setGender("Male");
		sb.setHeightBegin(60l);
		sb.setHeightEnd(72l);
		sb.setLanguages(Arrays.asList("Hindi", "Marathi"));
		sb.setLocationCountry(Arrays.asList("USA", "United Kingdom"));
		sb.setManglik("Yes");
		sb.setMaritalStatus(Arrays.asList("Married", "Unmarried"));
		sb.setRatingThreshold(3l);
		
		JSONSerializer s = new JSONSerializer();
		System.out.println(sb.toString());
		JSONObject jsonObject = (JSONObject)s.serializeAsJson(sb.getProperties());
		System.out.println(jsonObject.toString());
		Map<String, Object> map = s.parseMap(jsonObject);
		SearchBean s1 = new SearchBean();
		s1.setProperties(map);
		System.out.println(s1.toString());
	}
	
	  /**
     * Serialize the specified object as a JSONValue. The object to serialize must be an instance of:
     * - String
     * - Map
     * - List
     *

     * where O has the same constraints.
     */
    public static JSONValue serializeAsJson(Object object) {
        if (object instanceof Map) {
            Map<String, Object> map = (Map<String, Object>) object;
            JSONObject jsonObject = new JSONObject();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                String key = entry.getKey();
                Object value = entry.getValue();
                if(value != null){
                	JSONValue convertedValue = serializeAsJson(value);
                	jsonObject.put(key, convertedValue);
                }else{
                	System.out.println(key + " is null");
                	jsonObject.put(key, null);
                }
            }
            return jsonObject;
        }
        else if (object instanceof List) {
            List<String> list = (List<String>) object;
            JSONArray jsonArray = new JSONArray();
            for (int i = 0; i < list.size(); i++) {
                Object entry = list.get(i);
                JSONValue convertedValue = serializeAsJson(entry);
                jsonArray.set(i, convertedValue);
            }
            return jsonArray;
        }
        else if (object instanceof String) {
            return new JSONString((String) object);
        }
        else if (object instanceof Boolean) {
        	return JSONBoolean.getInstance(((Boolean) object).booleanValue());
        }
        else if (object instanceof Long) {
            return new JSONNumber(((Long) object).doubleValue());
        }
        else if (object instanceof Integer) {
        	return new JSONNumber(((Integer) object).doubleValue());
        }
        else {
            throw new RuntimeException("Unsupported state type: " + object.getClass());
        }
    }

    /**
     * Parse a JSONValue as follows:
     * -if the value is a JSONObject, parse into a Map
     * -if the value is a JSONArray, parse into a List
     * -if the value is a JSONString, parse into a String
     * -otherwise fail
     */
    public static Object parseObject(JSONValue jsonValue) {
        if (jsonValue == null) {
            return null;
        }else if (jsonValue.isObject() != null) {
            return parseMap(jsonValue.isObject());
        }
        else if (jsonValue.isArray() != null) {
            return parseList(jsonValue.isArray());
        }
        else if (jsonValue.isString() != null) {
            return jsonValue.isString().stringValue();
        }
        else if (jsonValue.isNumber() != null) {
            return Long.parseLong(jsonValue.isNumber().toString()) ;
        }
        else if (jsonValue.isBoolean() != null) {
        	return new Boolean(((JSONBoolean)jsonValue).booleanValue());
        }
        else {
            throw new RuntimeException("Failed to parse JSON: " + jsonValue.toString());
        }
    }

    /**
     * Parse the specified JSONObject into a Map. The JSONValue associated to
     * a key is parsed recursively using {@link #parseObject(JSONValue)}
     */
    public static Map<String, Object> parseMap(JSONObject jsonObject) {
        Map<String, Object> result = new HashMap<String, Object>();
        for (String key : jsonObject.keySet()) {
            JSONValue jsonValue = jsonObject.get(key);
            Object convertedValue = parseObject(jsonValue);
            result.put(key, convertedValue);
        }
        return result;
    }

    /**
     * Parse the specified JSONArray into a List. The JSONValues contained in the array are
     * parsed recursively using {@link #parseObject(JSONValue)}
     */
    public static Object parseList(JSONArray array) {
        List<String> result = new ArrayList<String>();
        for (int i = 0; i < array.size(); i++) {
            JSONValue jsonValue = array.get(i);
            Object convertedValue = parseObject(jsonValue);
            result.add((String)convertedValue);
        }
        return result;
    }
          
}
